import AudioKit
import AVFoundation
import SwiftUI

//: ## Multi-tap Delay
//: A multi-tap delay is a delay line where multiple 'taps' or outputs are
//: taken from a delay buffer at different points, and the taps are then
//: summed with the original. Multi-tap delays are great for creating
//: rhythmic delay patterns, but they can also be used to create sound
//: fields of such density that they start to take on some of the qualities
//: we'd more usually associate with reverb. - Geoff Smith, Sound on Sound

class MultiTapDelayConductor: ObservableObject, ProcessesPlayerInput {
    let engine = AudioEngine()
    let player = AudioPlayer()
    let buffer: AVAudioPCMBuffer

    init() {
        buffer = Cookbook.sourceBuffer

        var delays = [VariableDelay]()

        func multitapDelay(_ input: Node, times: [AUValue], gains: [AUValue]) -> Mixer {
            let mix = Mixer(input)
            var counter = 0
            zip(times, gains).forEach { (time, gain) -> Void in
                delays.append(VariableDelay(input, time: time))
                mix.addInput(Fader(delays[counter], gain: gain))
                counter += 1
            }
            return mix
        }

        engine.output = multitapDelay(player, times: [0.1, 0.2, 0.4], gains: [0.5, 2.0, 0.5])
    }

    func start() {
        do { try engine.start() } catch let err { Log(err) }
        player.scheduleBuffer(buffer, at: nil, options: .loops)
    }
    func stop() {
        engine.stop()
    }
}

struct MultiTapDelayView: View {
    @ObservedObject var conductor = MultiTapDelayConductor()

    var body: some View {
        VStack(spacing: 20) {
            Text("""
A multi-tap delay is a delay line where multiple 'taps' or outputs are taken from a delay buffer at different points, and the taps are then summed with the original. Multi-tap delays are great for creating rhythmic delay patterns, but they can also be used to create sound fields of such density that they start to take on some of the qualities we'd more usually associate with reverb.

- Geoff Smith, Sound on Sound
""")
            PlayerControls(conductor: conductor)
        }
        .padding()
        .navigationBarTitle(Text("MultiTap Delay Operation"))
        .onAppear {
            self.conductor.start()
        }
        .onDisappear {
            self.conductor.stop()
        }
    }
}

struct MultiTapDelay_Previews: PreviewProvider {
    static var previews: some View {
        MultiTapDelayView()
    }
}
